﻿namespace StyleCop.CSharp.JslRefactoringRules
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class TestLocalVariablesShouldBeSetWhereTheyAreDeclared : TestBase<RuleAnalyzer>
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="TestLocalVariablesShouldBeSetWhereTheyAreDeclared"/> class.
        /// </summary>
        public TestLocalVariablesShouldBeSetWhereTheyAreDeclared()
            : base(RuleAnalyzer.LocalVariablesShouldBeSetWhereTheyAreDeclared)
        {
        }
        #endregion Constructors

        [TestMethod]
        public void No_variables_is_OK()
        {
            this.TestMethod(
@"public int Method()
{
    return 5;
}");
        }

        [TestMethod]
        public void Fields_are_ignored()
        {
            // This doesn't really test that the field is ignored, just that it doesn't produce violations.
            this.TestSource(
                @"namespace MyNamespace
                {
                    public class Class
                    {
                        private int field;

                        public int Method()
                        {
                            return 5;
                        }
                    }
                }");
        }

        [TestMethod]
        public void Inline_setting_is_OK()
        {
            this.TestMethod(
@"public void Method()
{
    int variable = 5;
}");
        }

        [TestMethod]
        public void Variable_should_be_set_in_declaration()
        {
            this.TestMethod(
@"public void Method()
{
    int variable;
    variable = 5;
}",
                new ViolationInfo(4, "The variable 'variable' should be set in its declaration."));
        }

        [TestMethod]
        public void Variable_should_only_be_warned_once()
        {
            this.TestMethod(
@"public void Method()
{
    int variable;
    variable = 5;
    variable = 6;
}",
                new ViolationInfo(4, "The variable 'variable' should be set in its declaration."));
        }

        [TestMethod]
        public void Fields_setting_are_ignored()
        {
            this.TestSource(
                @"namespace MyNamespace
                {
                    public class Class
                    {
                        private bool variable;

                        public void Method()
                        {
                            bool variable;
                            this.variable = true;
                        }
                    }
                }");
        }

        [TestMethod]
        public void Works_with_multiple_declarations_and_assignments()
        {
            this.TestMethod(
@"public void Method()
{
    int variable1;
    bool variable2 = true;
    variable1 = 5;
}",
                new ViolationInfo(5, "The variable 'variable1' should be set in its declaration."));
        }

        [TestMethod]
        public void Variable_initialization_on_two_different_paths_is_OK()
        {
            this.TestMethod(
@"public void Method()
{
    int variable;
    if (true)
    {
        variable = 5;
    }
    variable = 6;
}");
        }

        [TestMethod]
        public void Catch_variables_are_ignored()
        {
            this.TestMethod(
@"public void Method()
{
    try
    {
    }
    catch (Exception ex)
    {
        throw ex;
    }
}");
        }

        [TestMethod]
        public void Throw_paths_are_ignored()
        {
            this.TestMethod(
@"public void Method()
{
    int variable;
    throw new Exception();
    variable = 5;
}");
        }

        [TestMethod]
        public void Throw_paths_are_skipped()
        {
            this.TestMethod(
@"public void Method()
{
    int variable;
    if (booleanValue)
    {
        throw new Exception();
    }

    variable = 5;
}",
                new ViolationInfo(9, "The variable 'variable' should be set in its declaration."));
        }
    }
}